package com.atguigu.tingshu.payment.service.impl;

import com.atguigu.tingshu.account.client.RechargeInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.account.RechargeInfo;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static com.mysql.cj.conf.PropertyKey.logger;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

	@Autowired
	private PaymentInfoService paymentInfoService;

	@Autowired
	private WxPayV3Config wxPayV3Config;

	@Autowired
	private RSAAutoCertificateConfig config;

	@Autowired
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private OrderInfoFeignClient orderInfoFeignClient;

	@Autowired
	private RechargeInfoFeignClient rechargeInfoFeignClient;


	@Override
	public Transaction wxNotify(HttpServletRequest request) {
		//	获取请求头中的数据;
		String wechatPaySerial = request.getHeader("Wechatpay-Serial");
		String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
		String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
		String wechatSignature = request.getHeader("Wechatpay-Signature");
		//	请求体不能更改；
		String requestBody = PayUtil.readData(request);
		// 构造 RequestParam
		RequestParam requestParam = new RequestParam.Builder()
				.serialNumber(wechatPaySerial)
				.nonce(wechatpayNonce)
				.signature(wechatSignature)
				.timestamp(wechatTimestamp)
				.body(requestBody)
				.build();
		// 初始化 NotificationParser
		NotificationParser parser = new NotificationParser(config);
		try {
			// 以支付通知回调为例，验签、解密并转换成 Transaction
			Transaction transaction = parser.parse(requestParam, Transaction.class);
			//	返回数据;
			return transaction;
		} catch (ValidationException e) {
			// 签名验证失败，返回 401 UNAUTHORIZED 状态码
			log.error("sign verification failed", e);
		}
		//	返回空对象
		return null;
	}

	/**
	 * 查询支付状态
	 * @param orderNo 订单编号 等于微信系统中 out_trade_no
	 * @return
	 */
	@Override
	public Transaction queryPayStatus(String orderNo) {
		//	根据商户订单号查询;
		QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
		queryRequest.setMchid(wxPayV3Config.getMerchantId());
		queryRequest.setOutTradeNo(orderNo);

		try {
			//	构建service
			JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
			Transaction result = service.queryOrderByOutTradeNo(queryRequest);
			System.out.println(result.getTradeState());
			//	返回对象
			return  result;
		} catch (ServiceException e) {
			// API返回失败, 例如ORDER_NOT_EXISTS
			System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
			System.out.printf("reponse body=[%s]\n", e.getResponseBody());
		}
		return null;
	}

	@Override
	public Map<String, Object> createJsapi(String orderNo, String paymentType, Long userId) {
		//	1.	封装数据放回map; 5个key;	2.	保存交易记录信息;
		Map<String, Object> result = new HashMap<>();
		//	声明一个充值变量;
		BigDecimal totalAmount = new BigDecimal("0.00");
		//	判断使用微信支付的用途;
		if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)){
			//	根据订单编号查询订单对象;
			Result<OrderInfo> orderInfoResult = this.orderInfoFeignClient.getOrderInfo(orderNo);
			Assert.notNull(orderInfoResult, "远程调用获取订单信息失败");
			OrderInfo orderInfo = orderInfoResult.getData();
			//	判断状态：
			if (null != orderInfo && !SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())){
				//	抛出异常;
				throw new GuiguException(ResultCodeEnum.DATA_ERROR.getCode(),"订单状态异常");
			}
			totalAmount = orderInfo.getOrderAmount();
		} else {
			//	充值;
			Result<RechargeInfo> rechargeInfoResult = rechargeInfoFeignClient.getRechargeInfo(orderNo);
			Assert.notNull(rechargeInfoResult, "远程调用获取充值信息失败");
			RechargeInfo rechargeInfo = rechargeInfoResult.getData();
			Assert.notNull(rechargeInfo, "远程调用获取充值信息失败");
			//	获取金额；
			totalAmount = rechargeInfo.getRechargeAmount();
		}

		//	保存交易记录;
		paymentInfoService.savePaymentInfo(userId, paymentType, orderNo,totalAmount);

		// 使用微信支付公钥的RSA配置
		JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
		// 跟之前下单示例一样，填充预下单参数
		PrepayRequest request = new PrepayRequest();
		Amount amount = new Amount();
		//	1分钱;
		amount.setTotal(1);
		request.setAmount(amount);
		request.setAppid(wxPayV3Config.getAppid());
		request.setMchid(wxPayV3Config.getMerchantId());
		request.setDescription("测试商品标题");
		request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
		//	orderNo:叫商户订单号!
		request.setOutTradeNo(orderNo);
		//	设置支付者;
		Payer payer = new Payer();
		//	获取用户信息;
		Result<UserInfoVo> infoVoResult = userInfoFeignClient.getUserInfo(userId);
		Assert.notNull(infoVoResult, "远程调用获取用户信息失败");
		UserInfoVo userInfoVo = infoVoResult.getData();
		Assert.notNull(userInfoVo, "远程调用获取用户信息失败");
		payer.setOpenid(userInfoVo.getWxOpenId());
		request.setPayer(payer);
		//	request.setTimeExpire();
		// response包含了调起支付所需的所有参数，可直接用于前端调起支付
		PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
		//	封装结果;
		result.put("timeStamp", response.getTimeStamp()); // 时间戳
		result.put("nonceStr", response.getNonceStr());   // 随机字符串
		result.put("package", response.getPackageVal());  // 订单详情扩展字符串
		result.put("signType", response.getSignType());   // 签名方式
		result.put("paySign", response.getPaySign());     // 签名
		//	返回数据
		return result;
	}
}
